﻿using System;
using System.IO;
using System.Threading;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;


namespace LuaExecuter {

	using LuaCore = KopiLua.Lua;

	public class CsCallLuaExecuter {

		private static LuaCore.lua_State L;

		public CsCallLuaExecuter () {
			
		}

		public void execute () {
			Console.WriteLine ("CsCallLuaExecuter");

			load ();
			Console.WriteLine ("==========pushLuaField================");
			pushLuaField ();
			Console.WriteLine ();
			Console.WriteLine ("==========getLuaGlobal================");
			getLuaGlobal ();
			Console.WriteLine ();
			Console.WriteLine ("==========getLuaTable=================");
			getLuaTable ();
			Console.WriteLine ();
			Console.WriteLine ("==========newLuaTable=================");
			newLuaTable ();
			Console.WriteLine ();
			Console.WriteLine ("==========callLuaFunction=============");
			callLuaFunction ();
			Console.WriteLine ();
			Console.WriteLine ("==========setLuaFunction==============");
			setLuaFunction ();
			Console.WriteLine ();

			close ();
		}

		public void load () {
			string line;
			string path = Directory.GetCurrentDirectory () + "/../../test.lua";
			Console.WriteLine (path);

			var sb = new System.Text.StringBuilder ();
			var file = new StreamReader (path);
			while ((line = file.ReadLine ()) != null) {
				sb.AppendLine (line);
			}
			file.Close ();

			L = LuaCore.luaL_newstate ();
			LuaCore.luaL_openlibs (L);
			LuaCore.luaL_loadstring (L, sb.ToString ());
			LuaCore.lua_pcall (L, 0, 0, 0);
		}

		public void close () {
			LuaCore.lua_close (L);
		}

		public void pushLuaField () {
			LuaCore.lua_pushstring (L, "Helloworld");
			LuaCore.lua_pushnumber (L, 100);
			LuaCore.lua_pushnumber (L, 200);
			LuaCore.lua_pushnumber (L, 300);
			LuaCore.lua_pushnumber (L, 400);
			LuaCore.lua_pushnumber (L, 500);
			LuaCore.CharPtr achar = LuaCore.lua_tostring (L, -1);
			Console.WriteLine (achar.ToString ());
			LuaCore.lua_settop (L, 5);
			stackDump (L);
			LuaCore.lua_settop (L, 0);
		}

		public void getLuaGlobal () {
			LuaCore.lua_getglobal (L, "width");
			LuaCore.lua_getglobal (L, "height");
			if (LuaCore.lua_isnumber (L, -2) == 0)
				Console.WriteLine ("`width' should be a number");
			if (LuaCore.lua_isnumber (L, -1) == 0)
				Console.WriteLine ("`height' should be a number");
			int width = (int)LuaCore.lua_tonumber (L, -2);
			int height = (int)LuaCore.lua_tonumber (L, -1);
			Console.WriteLine ("width:" + width);
			Console.WriteLine ("height:" + height);
			stackDump (L);
			LuaCore.lua_settop (L, 0);
		}

		public void getLuaTable () {
			LuaCore.lua_getglobal (L, "background");
			if (!LuaCore.lua_istable (L, -1))
				Console.WriteLine ("`background' is not a valid color table");
			int red = getfield (new LuaCore.CharPtr ("r"));
			int green = getfield (new LuaCore.CharPtr ("g"));
			int blue = getfield (new LuaCore.CharPtr ("b"));

			Console.WriteLine (red + ":" + green + ":" + blue);
			stackDump (L);
			LuaCore.lua_settop (L, 0);
		}

		public void newLuaTable () {
			setcolor ("t1", 100, 150, 200);
			LuaCore.lua_getglobal (L, "t1");
			if (!LuaCore.lua_istable (L, -1))
				Console.WriteLine ("`background' is not a valid color table");
			int red1 = getfield (new LuaCore.CharPtr ("r"));
			int green1 = getfield (new LuaCore.CharPtr ("g"));
			int blue1 = getfield (new LuaCore.CharPtr ("b"));

			Console.WriteLine (red1 + ":" + green1 + ":" + blue1);
			stackDump (L);
			LuaCore.lua_settop (L, 0);
		}

		public void callLuaFunction () {
			double r = f (2, 3);
			Console.WriteLine (r);
			stackDump (L);
			LuaCore.lua_settop (L, 0);
		}

		public void setLuaFunction () {
			LuaCore.lua_pushcfunction (L, myfun);
			LuaCore.lua_setglobal (L, "myfun");
			LuaCore.luaL_loadstring (L, "print ( myfun(5) )");
			LuaCore.lua_pcall (L, 0, 0, 0);
			stackDump (L);
			LuaCore.lua_settop (L, 0);
		}

		static int myfun (LuaCore.lua_State aL) {
			double d = LuaCore.lua_tonumber (aL, 1); /* get argument */
			d = d * d;
			LuaCore.lua_pushnumber (aL, d); /* push result */
			return 1; /* number of results */
		}


		static double f (double x, double y) {
			double z;
			/* push functions and arguments */
			LuaCore.lua_getglobal (L, "f"); /*functiontobecalled*/
			LuaCore.lua_pushnumber (L, x); /* push 1st argument */
			LuaCore.lua_pushnumber (L, y); /* push 2nd argument */
						       /* do the call (2 arguments, 1 result) */
			if (LuaCore.lua_pcall (L, 2, 1, 0) != 0)
				Console.WriteLine ("error running function " + LuaCore.lua_tostring (L, -1));
			/* retrieve result */
			if (LuaCore.lua_isnumber (L, -1) == 0)
				Console.WriteLine ("function `f' must return a number");
			z = LuaCore.lua_tonumber (L, -1);
			LuaCore.lua_pop (L, 1); /* pop returned value */
			return z;
		}

		static void setcolor (LuaCore.CharPtr name, int r, int g, int b) {
			LuaCore.lua_newtable (L);
			setfield ("r", r);
			setfield ("g", g);
			setfield ("b", b);
			LuaCore.lua_setglobal (L, name);
		}

		static void setfield (LuaCore.CharPtr index, int value) {
			LuaCore.lua_pushstring (L, index);
			LuaCore.lua_pushnumber (L, (double)value / 255.0);
			LuaCore.lua_settable (L, -3);
		}

		static int getfield (LuaCore.CharPtr key) {

			int result = 0;
			LuaCore.lua_pushstring (L, key);
			LuaCore.lua_gettable (L, -2);
			if (LuaCore.lua_isnumber (L, -1) == 0)
				Console.WriteLine ("invalid component in background color");
			else {
				result = (int)(LuaCore.lua_tonumber (L, -1) * 255);
				LuaCore.lua_pop (L, 1);
			}
			return result;

		}


		static void stackDump (LuaCore.lua_State L) {

			Console.WriteLine ("Stack:");

			int i;
			int top = LuaCore.lua_gettop (L);
			for (i = 1; i <= top; i++) { /*repeatforeachlevel*/
				int t = LuaCore.lua_type (L, i);
				switch (t) {
				case LuaCore.LUA_TSTRING:
					Console.Write (LuaCore.lua_tostring (L, i)); break;
				case LuaCore.LUA_TBOOLEAN:
					Console.Write (LuaCore.lua_toboolean (L, i) == 1 ? "true" : "false"); break;
				case LuaCore.LUA_TNUMBER:
					Console.Write (LuaCore.lua_tonumber (L, i)); break;
				default:
					Console.Write (LuaCore.lua_typename (L, t)); break;
				}
				Console.Write ("|"); /* put a separator */
			}
			Console.WriteLine ();
		}

	}
}

